Implicitly Unwrapped Optionals in Swift

文章翻译自 Command Shift 的 Implicitly Unwrapped Optionals in Swift

Implicitly Unwrapped Optionals(隐式解包可选值) 乍看之下可能没有意义,它是一个可选值,但是你总是要假定它是否有值,为啥还要这么个东西?

根据这些年的工作经历,对属性最主要的使用是 set 方法,而不是初始化。这非常适合 Cocoa 对象的生命周期。例如,view ,以及你在 loadviewviewdidload 方法下创建的 subviews,他们会被延迟加载,其时间点并不跟 viewController 被初始化的时间点一致。

如果 outlets 被声明为 var 属性,通常会设置一个初始值,或者设置一个初始化方法,否则编译器不会通过,设置属性类型为 optional 将不再需要这个要求,因为 optional 有一个默认的 .None 值,然后在代码里你必须对它进行解包。

var label : UILabel?
...
label!.text = "Unwrapped label"

这个是可行的,但是太难看了。

将属性设置为 Implicitly Unwrapped Optional 可读性更强,且功能一样。

var label: UILabel!
...
label.text = "Unwrapped label"

这不仅仅用于 UI 组件,任何你想要传递给另一个对象,但是没有初始化方法,最好也设置成 Implicitly Unwrapped Optional。苹果文档是这么说的:

“When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.”

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.”

Implicitly Unwrapped Optional 还可以确认是否有值。

if label != nil {
label.text = "yes,there’s a label here"
}

苹果推荐 Implicitly Unwrapped Optionals 只使用于那些非 nil 的确定值。预想的使用场景就是赋值,而不仅仅是初始化。

另一个使用场景是在实现或重载 Cocoa 的方法,

Because Objective-C does not make any guarantees that an object is non–nil, Swift makes all classes in argument types and return types optional in imported Objective-C APIs. Before you use an Objective-C object, you should check to ensure that it is not missing.

In some cases, you might be absolutely certain that an Objective-C method or property never returns a nil object reference. To make objects in this special scenario more convenient to work with, Swift imports object types as implicitly unwrapped optionals. Implicitly unwrapped optional types include all of the safety features of optional types. In addition, you can access the value directly without checking for nil or unwrapping it yourself.

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.”

因此当你在实现某个代理方法的时候,你可以这么做:

func tableView(tableView: UITableView! numberOfRowsInSection section: Int) -> Int {}

tableView 被作为一个 Implicitly Unwrapped Optional 传递。你可以确定 tableView 确实被传递进来,从而不需要确认 tableView 是否为 nil

Optional 是权衡利弊的结果。一方面我们得到了统一表达“空值”的方式(不在需要 NSNotFoundNSIntegerMax,-1,0 来表达没有值),但如这篇文章所说,我们失去了发送 nil 的便捷安全。